package sell

import (
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
	"learn/smart/config"
	"learn/smart/fetcher"
	"learn/smart/parser"
	"net/url"
	"strconv"
	"strings"
	"time"
	"learn/smart/util"
	"sync"
)

type Sell struct {
	Fetcher *fetcher.Fetcher
	User    *config.User
	isStop  bool
	logger  util.Logger
}

//商城在售信息
type ItemResult struct {
	Succ      bool
	Is_More   bool
	Page_No   int
	Show_Data []Item
}

//在售饰品信息
type Item struct {
	Id         int
	Product_Id int
	Unit_Price string
	Name       string
	NewPrice   float64
}

//库存信息
type InventoryResult struct {
	Is_More   bool
	Message   string
	Page_No   int
	Show_Data []InventoryItem
	Succ      bool
}

//库存饰品信息
type InventoryItem struct {
	Name             string
	Id               int
	Marker_Hash_Name string
}

type FormItem struct {
	Id         int     `json:"id"`
	Unit_Price float64 `json:"unit_price"`
	Fee_Price  float64 `json:"fee_price"`
}

func (s *Sell) Init() {
	name := "IGXE-" + s.User.Username
	s.logger = util.Logger{Name: name}
}

func InitSell(fetcher *fetcher.Fetcher, user *config.User) Sell {
	return Sell{Fetcher: fetcher, User: user}
}

func (s *Sell) filterItems(items []Item) []Item {
	var fItems []Item
	var wg sync.WaitGroup
	for _, item := range items {
		wg.Add(1)
		go func(item Item) {
			err := s.filterItem(&item)
			if err != nil {
				s.logger.Message(err.Error())
			} else {
				fItems = append(fItems, item)
			}
			wg.Done()
		}(item)
	}

	wg.Wait()

	return fItems
}

func (s *Sell) filterItem(item *Item) error {
	unitPrice, _ := strconv.ParseFloat(item.Unit_Price, 64)
	if unitPrice >= 100 {
		msg := fmt.Sprintf("饰品: %s, 价格超过100", item.Name)
		return errors.New(msg)
	}

	item.Name = strings.TrimSpace(item.Name)
	oItem := parser.GetOriginItem(item.Name)

	onSellLowestItem, err := parser.GetIgxeOnSellLowestItem(item.Product_Id)
	if err != nil {
		return err
	}
	if onSellLowestItem.Id == item.Id {
		msg := fmt.Sprintf("%s该饰品已经是最低价了", item.Name)
		return errors.New(msg)
	}

	onSellLowest, err := strconv.ParseFloat(onSellLowestItem.Unit_Price, 64)
	if err != nil {
		return err
	}

	var allowed float64

	if oItem.IsExtra == true {
		lowest, err := parser.GetLowestPriceByName(oItem.OriginName)
		if err != nil {
			s.logger.Message("%v", err)
			return err
		}

		allowed = lowest + oItem.ExtraPrice
	} else {
		lowest, err := parser.GetLowestPriceFromHistory(item.Name)
		if err != nil {
			s.logger.Message("%v\n", err)
			return err
		}
		allowed = lowest
	}

	newPriceStr := fmt.Sprintf("%.2f", onSellLowest-0.01)
	newPrice, _ := strconv.ParseFloat(newPriceStr, 64)

	s.logger.Message("获取饰品: %s, 当前在售最低价格: %f, 允许最低价格: %f, 新售价: %f",
		item.Name, onSellLowest, allowed, newPrice)

	if newPrice < allowed {
		return errors.New("价格过低, 不允许再进行压价")
	}

	item.NewPrice = newPrice
	return nil
}

func (s *Sell) Sell(items []Item) error {
	inventoryItems := s.GetAllInventory()

	var form []FormItem

	if len(inventoryItems) > 0 {
		for _, iItems := range inventoryItems {
			for _, item := range items {
				if strings.TrimSpace(iItems.Name) == item.Name {
					form = append(form, FormItem{Id: iItems.Id, Unit_Price: item.NewPrice, Fee_Price: 0})
				}
			}
		}

		err := s.doSell(form)
		if err != nil {
			return err
		}
	}

	return nil
}

func (s *Sell) doSell(form []FormItem) error {
	data := url.Values{}
	data.Add("csrfmiddlewaretoken", s.User.CSRFToken)
	formObj, _ := json.Marshal(form)
	formStr := string(formObj)

	data.Add("trades", formStr)
	data.Add("trade_pwd", s.User.PayPassword)
	headers := make(map[string]string)
	headers["X-Requested-With"] = "XMLHttpRequest"

	s.logger.Message(string(formStr))

	resp, err := s.Fetcher.Post("/igxe/sale/570", data, headers)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	contents, err := fetcher.GetContents(resp)
	if err != nil {
		return err
	}

	s.logger.Message("请求上架出售: %s", contents)

	return nil
}

func (s *Sell) OffSale(items []Item) error {
	s.logger.Message("开始下架Items: %v\nlen:%d", items, len(items))
	var ids []string

	for _, item := range items {
		ids = append(ids, strconv.Itoa(item.Id))
	}

	path := fmt.Sprintf("/down_sale/570?ids=%s", strings.Join(ids, ","))
	s.logger.Message("开始请求下架, path: %s\n", path)
	resp, err := s.Fetcher.Get(path, nil)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		msg := fmt.Sprintf("下架请求,StautsCode: %d", resp.StatusCode)
		return errors.New(msg)
	}

	contents, _ := fetcher.GetContents(resp)

	s.logger.Message("下架请求返回结果: %s\n", contents)

	return nil
}

func (s *Sell) GetItem(page int) (ItemResult, error) {
	uri := fmt.Sprintf("/sell/data/570?page_no=%d&sort_key=%d&sort_rule=%d&status_type=%d",
		page, 2, 2, 9)

	resp, err := s.Fetcher.Get(uri, nil)

	var result ItemResult

	if err != nil {
		return result, err
	}
	defer resp.Body.Close()

	contents, err := fetcher.GetContents(resp)

	if err != nil {
		return result, err
	}

	json.Unmarshal(contents, &result)

	return result, nil
}

func (s *Sell) GetInventory(page int) (InventoryResult, error) {
	path := fmt.Sprintf(
		"/inventory/igxe/data/570?page_no=%d&sort_key=1&sort_rule=2&status_type=1&source_type=9",
		page)
	resp, err := s.Fetcher.Get(path, nil)
	var result InventoryResult
	if err != nil {
		return result, err
	}
	defer resp.Body.Close()

	contents, err := fetcher.GetContents(resp)

	if err != nil {
		return result, err
	}
	json.Unmarshal(contents, &result)

	return result, nil
}

func (s *Sell) GetAllInventory() []InventoryItem {
	page := 1

	var items []InventoryItem

	for {
		iResult, err := s.GetInventory(page)

		if err != nil {
			s.logger.Message("获取库存信息page: %d 失败, error: %v", page, err)
		}
		items = append(items, iResult.Show_Data...)
		if iResult.Succ != true || iResult.Is_More == false {
			break
		}

		page++
	}
	return items
}

func (s *Sell) Start() {
	page := 1
	s.isStop = false
	for {
		s.logger.Message("开始请求 page: %d ", page)
		result, _ := s.GetItem(page)

		if len(result.Show_Data) == 0 {
			fmt.Println(result)
			s.logger.Message("改价请求已经完成, 一小时后进行下一次")
			<-time.Tick(time.Hour)
			s.Restart()
			break
		}

		items := s.filterItems(result.Show_Data)

		err := s.OffSale(items)

		if err != nil {
			s.logger.Message("请求下架失败, err: %v", err)
		} else {
			err := s.Sell(items)

			if err != nil {
				s.logger.Message("请求上架失败, err: %v", err)
			}
		}
		s.logger.Message("第 %d 页请求完成, %d 分钟后进行下一次请求", page, 5)
		page++
		<-time.After(5 * time.Minute)
	}
}

func (s *Sell) Restart() {
	s.Start()
}

func (s *Sell) Stop() {
	s.isStop = true
}
